
package cn.e2win.biz.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class GenericsUtils {
	
	static Log logger = LogFactory.getLog(GenericsUtils.class);
	
	public static final int ADD_TYPE = 0;
	public static final int UPDATE_TYPE = 1;
	/**
	 * Get generic class from a class.
	 * 
	 * @param clazz
	 *            a class
	 * @return generic class
	 */
	public static Class getGenericClass(Class clazz) {
		return getGenericClass(clazz, 0);
	}

	/**
	 * Get generic class from a class.
	 * 
	 * @param clazz
	 *            a class
	 * @param index
	 *            parameter position
	 * @return generic class
	 */
	public static Class getGenericClass(Class clazz, int index) {
		Type genType = clazz.getGenericSuperclass();
		if (genType instanceof ParameterizedType) {
			Type[] params = ((ParameterizedType) genType)
					.getActualTypeArguments();
			if ((params != null) && (params.length >= (index - 1))) {
				return (Class) params[index];
			}
		}
		return null;
	}
	
	/**
	 * get generic class pk by Annotation @ID
	 * @param t
	 * @return
	 */
	public static Object getPKValue(Object newObj) {
		Field idField = null;
		Field[] fields = newObj.getClass().getDeclaredFields();
		//寻找ＩＤ
		for (int i = 0; i < fields.length; i++) {
			 if (fields[i].isAnnotationPresent(Id.class)) {
				idField = fields[i];
				break;
			 }
		}
		if (idField != null) {
			//根据ID获得数据库中的对象
			String fieldNameString = idField.getName();
			String getMethodName = method2field("get", fieldNameString);
			Method method;
			try {
				method = newObj.getClass().getMethod(getMethodName);
				return method.invoke(newObj, null);
			} catch (Exception e) {
				logger.error(e);
			} 
		}
		return null;
	}
	
	/**
	 * set object which in DB, by new object values
	 * ！！！！！只能修改一些简单字段的值，如要修改一对多，多对多这种映射关系，需要先load，再setvalue,再save.此方法不适合！！！
	 * @param t
	 * @return
	 */
	public static void setFieldValue(Object newObj, Object objOld) {
		Field[] fields = newObj.getClass().getDeclaredFields();
		try {
			List<Field> fieldList = getDBFieldList(newObj.getClass());
			for (Field field:fieldList) {
				
				String oneOfFieldName = field.getName();
				String getMethod = method2field("get", oneOfFieldName);
				String setMethod = method2field("set", oneOfFieldName);
				Method oneOfGetMethod = newObj.getClass().getMethod(getMethod);
				Method oneOfSetMethod = newObj.getClass().getMethod(setMethod, field.getType());
				Object fieldValue = oneOfGetMethod.invoke(newObj, null);
				if(fieldValue != null){
					oneOfSetMethod.invoke(objOld, fieldValue);
				}
			}
		} catch (Exception e) {
			logger.error(e);
		}
	}
	
	public static List<Field> getDBFieldList(Class clazz){
		List<Field> list = new ArrayList<Field>();		
		Field[] fields1 = clazz.getDeclaredFields();		
		Field[] fields2 = clazz.getSuperclass().getDeclaredFields();
		Field[] fields3 = clazz.getSuperclass().getSuperclass().getDeclaredFields();
		Field[] fields4 = null;
		Class fields4Class = clazz.getSuperclass().getSuperclass();
		if(fields4!=null){
			fields4 = fields4Class.getSuperclass().getDeclaredFields();
		}
		List<Field> fields = new ArrayList<Field>(Arrays.asList(fields1));
		fields.addAll(Arrays.asList(fields2));
		fields.addAll(Arrays.asList(fields3));
		if(fields4!=null) {
			fields.addAll(Arrays.asList(fields4));
		}
		
		for (Field field: fields) {
			//except: private static final long serialVersionUID = 1L
			if (isStaticFinal(field)) {
				continue;
			} else if (field.isAnnotationPresent(Transient.class)) {
				//不是数据库中字段
				continue;
			} else if (field.isAnnotationPresent(ManyToMany.class)) {
				continue;
			} else if (field.isAnnotationPresent(OneToMany.class)) {
				continue;
			} else if (field.isAnnotationPresent(ManyToOne.class)) {
				continue;
			}
			list.add(field);
		}
		return list;
		
	}
	
	
	private static String method2field(String setOrGetString, String attrName) {
		return setOrGetString + attrName.substring(0, 1).toUpperCase().concat(attrName.substring(1));
	}
	
	 /**
     * 判断字段是否是公共静态常量（"public static final"）
     *
     * @param field
     * @return
     */
	private static boolean isStaticFinal(Field field) {
        int modifiers = field.getModifiers();
        return (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers));
    }
	


/**

* 取Bean的属性和值对应关系的MAP

* @param bean

* @return Map

*/
/*
public static Map<String, Object> getFieldValueMap(Object bean) {
	Class<?> cls = bean.getClass();
	Map<String, Object> valueMap = new HashMap<String, Object>();
	// 取出bean里的所有方法
	Method[] methods = cls.getDeclaredMethods();
	Field[] fields = cls.getDeclaredFields();
	for (Field field : fields) {
		try {
			//String fieldType = field.getType().getSimpleName();
			String fieldGetName = parGetName(field.getName());
			if (isMethod(methods, fieldGetName)) {				
				Method fieldGetMet = cls.getMethod(fieldGetName, new Class[] {});	
				Object fieldVal = fieldGetMet.invoke(bean, new Object[] {});	
				String result = null;	
				if ("Date".equals(fieldType)) {	
					result = fmtDate((Date) fieldVal);	
				} else {	
					if (null != fieldVal) {	
						result = String.valueOf(fieldVal);	
					}
				}
				valueMap.put(field.getName(), fieldVal);	
			}	
		} catch (Exception e) {	
			continue;	
		}
	}
	return valueMap;
}*/

/**

* set属性的值到Bean

* @param bean

* @param valMap

*/
/*
	public static void setFieldValue(Object bean, Map<String, Object> valMap) {
		Class<?> cls = bean.getClass();
		// 取出bean里的所有方法
		Method[] methods = cls.getDeclaredMethods();
		Field[] fields = cls.getDeclaredFields();
		for (Field field : fields) {
			try {
				String fieldSetName = parSetName(field.getName());
				if (isMethod(methods, fieldSetName)) {
					Method fieldSetMet = cls.getMethod(fieldSetName, field.getType());
					Object value = valMap.get(field.getName());
					if (null != value && !"".equals(value)) {
						fieldSetMet.invoke(bean, value);
						
						String fieldType = field.getType().getSimpleName();
						if ("String".equals(fieldType)) {
							fieldSetMet.invoke(bean, value);
						} else if ("Date".equals(fieldType)) {
							Date temp = parseDate(value);
							fieldSetMet.invoke(bean, temp);
						} else if ("Integer".equals(fieldType)|| "int".equals(fieldType)) {
							Integer intval = Integer.parseInt(value);
							fieldSetMet.invoke(bean, intval);
						} else if ("Long".equalsIgnoreCase(fieldType)) {
							Long temp = Long.parseLong(value);
							fieldSetMet.invoke(bean, temp);
						} else if ("Double".equalsIgnoreCase(fieldType)) {
							Double temp = Double.parseDouble(value);
							fieldSetMet.invoke(bean, temp);
						} else if ("Boolean".equalsIgnoreCase(fieldType)) {
							Boolean temp = Boolean.parseBoolean(value);
							fieldSetMet.invoke(bean, temp);
						} else {
							System.out.println("not supper type" + fieldType);
						}
					}					
				}
			} catch (Exception e) {
			continue;
			}
		}
	}
	
	public static Serializable getPK(Object obj){
		
		return null;
	}

	public static String parSetName(String fieldName){
		return "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
	}
	public static String parGetName(String fieldName){
		return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
	}
	public static boolean isMethod(Method[] methods, String methodName){
		for(Method m : methods){
			if(m.getName().equals(methodName)){
				return true;
			}
		}
		return false;
	}
	public static Date parseDate(String strDate){
		if(StringUtils.isEmpty(strDate)){
			return null;
		}
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try {
			return sdf.parse(strDate);
		} catch (ParseException e) {
			return null;
		}
	}

	public static String fmtDate(Date date){
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
		return sdf.format(date);
	}*/
}
